<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />

    <title>reveal-md</title>
    <link rel="stylesheet" href="./css/reveal.css" />
    <link rel="stylesheet" href="./css/theme/league.css" id="theme" />
    <link rel="stylesheet" href="./css/highlight/zenburn.css" />
    <link rel="stylesheet" href="./css/print/paper.css" type="text/css" media="print" />

  </head>
  <body>
    <div class="reveal">
      <div class="slides"><section  data-markdown><script type="text/template">### framework7开发实践(上)
分享人：张航晨
</script></section><section  data-markdown><script type="text/template">###  目录

- framework7介绍
- page(页面)
- routes(路由)
- route api(路由方法)
- template7
- swipeout
</script></section><section  data-markdown><script type="text/template">
### framework7是什么
> <font size=4>Framework7是一个免费的开源HTML移动框架，用于开发具有iOS或Android（Material）原生外观的混合移动应用程序或Web应用程序。 
它也是一个不可或缺的原型应用工具，可以在需要时尽快制作工作应用原型。
Framework7由Vladimir Kharlampidi（[iDangero.us](http://idangero.us/ "iDangero.us")）创建。
Framework7的主要目的是让您有机会轻松，清晰地创建HTML，CSS和JavaScript的iOS和Android（Material）应用程序。 
Framework7并非与所有平台兼容， 它仅专注于iOS和Android（Material），以带来最佳体验和简洁性。
如果您决定构建iOS和Android混合应用程序（Cordova或PhoneGap），或开发一个看起来像是原生iOS或Android（Material）应用程序的Web应用程序，Framework7是绝佳的选择。
</script></section><section  data-markdown><script type="text/template">### 创建一个app
创建一个html文件，并添加html结构
```html
<!DOCTYPE html>
<html>
  <head>
    <!-- Required meta tags-->
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no, minimal-ui, viewport-fit=cover">
    <meta name="apple-mobile-web-app-capable" content="yes">
    <!-- Color theme for statusbar -->
    <meta name="theme-color" content="#2196f3">
    <!-- Your app title -->
    <title>My App</title>
    <!-- Path to Framework7 Library Bundle CSS -->
    <link rel="stylesheet" href="path/to/framework7.bundle.min.css">
    <!-- Path to your custom app styles-->
    <link rel="stylesheet" href="path/to/my-app.css">
  </head>
  <body>
    <!-- App root element -->
    <div id="app">
      <!-- Statusbar overlay -->
      <div class="statusbar"></div>

      <!-- Your main view, should have "view-main" class -->
      <div class="view view-main">
        <!-- Initial Page, "data-name" contains page name -->
        <div data-name="home" class="page">

          <!-- Top Navbar -->
          <div class="navbar">
            <div class="navbar-inner">
              <div class="title">Awesome App</div>
            </div>
          </div>

          <!-- Bottom Toolbar -->
          <div class="toolbar toolbar-bottom">
            <div class="toolbar-inner">
              <!-- Toolbar links -->
              <a href="#" class="link">Link 1</a>
              <a href="#" class="link">Link 2</a>
            </div>
          </div>

          <!-- Scrollable page content -->
          <div class="page-content">
            <p>Page content goes here</p>
            <!-- Link to another page -->
            <a href="/about/">About app</a>
          </div>
        </div>
      </div>
    </div>
    <!-- Path to Framework7 Library Bundle JS-->
    <script type="text/javascript" src="path/to/framework7.bundle.min.js">__SCRIPT_END__
    <!-- Path to your app js-->
    <script type="text/javascript" src="path/to/my-app.js">__SCRIPT_END__
  </body>
</html>
```
</script></section><section  data-markdown><script type="text/template">
初始化my-app.js
```js
var app = new Framework7({
  // App root element
  root: '#app',
  // App Name
  name: 'My App',
  // App id
  id: 'com.myapp.test',
  // Enable swipe panel
  panel: {
    swipe: 'left',
  },
  // Add default routes
  routes: [
    {
      path: '/about/',
      url: 'about.html',
    },
  ],
  // ... other parameters
});

var mainView = app.views.create('.view-main');
```
大功告成！</script></section><section  data-markdown><script type="text/template">
### page(页面)
Page是用于显示应用内容的主要组件（容器）之一。

页面的基本布局
```html
<div class="page" data-name="home">
  <div class="page-content">
    所有的内容
  </div>
</div>
```
</script></section><section  data-markdown><script type="text/template">page事件

<font size=4>

事件|说明
-|-
page:mounted | 刚刚插入DOM的新页面将触发事件,或者将具有keepAlive路由的页面挂载/附加到DOM
page:init | 在Framework7初始化所需页面的组件和导航栏后，将触发事件
page:reinit | 导航到已初始化的页面时将触发此事件。
page:beforein | 当所有内容都已初始化并且页面已准备好插入视图（进入活动/当前位置）时，将触发事件
page:afterin | 页面插入视图后将触发事件
page:beforeout | 事件将在页面转换出视图之前触发
page:afterout | 页面转换出视图后将触发事件
page:beforeunmount | 当具有keepAlive路由的页面将从DOM卸载/分离时，将触发事件
page:beforeremove | 将在从DOM中删除页面之前触发事件。 如果您需要分离某些事件/销毁一些插件以释放内存，此事件可能非常有用。 keepAlive路由不会触发此事件
</script></section><section  data-markdown><script type="text/template">
### routes(路由)
路由基本属性
<font size=4>

属性 | 含义
- | -
name | 路由名称，例如 home
path | 路由path，用来匹配路径
options | 添加可选的options

例如
```js
{
    name: 'news',
    path: '/news/',
    url: './pages/news.html',
    options: {
        animate: false,
    },
}
```
</script></section><section  data-markdown><script type="text/template">
路由的content属性，定义应如何（从哪里/什么）加载内容
<font size=4>

属性 | 类型 | 含义
- | - | -
content | string | 从指定的内容字符串创建动态页面
url | string | 通过Ajax加载页面内容
template | string/function |从传递的Template7模板字符串或函数加载页面内容
templateUrl | string | 通过Ajax从url加载页面内容，并使用Template7进行编译
component | object | 从传递的Framework7路由器组件加载页面
componentUrl | string | 通过Ajax将页面加载为组件
async | function(routeTo, routeFrom, resolve, reject) | 需要异步操作和返回所需的路由内容和选项
</script></section><section  data-markdown><script type="text/template">
路由额外的Options
<font size=4>

属性 | 类型 | 含义
- | - | -
animate | boolean | 页面是否应该设置动画（覆盖默认路由器设置）
history | boolean | 是否应将页面保存在路由器历史记录中
pushState | boolean | 页面是否应保存在浏览器状态。 如果您使用pushState，那么您可以传递false以防止路由获取浏览器历史记录
reloadCurrent | boolean | 用路由中的新页面替换当前页面
reloadPrevious | boolean | 用路线中的新页面替换历史记录中的上一页
reloadAll | boolean | 加载新页面并从历史记录和DOM中删除所有以前的页面
context | object | Template7/Component页面的自定义/扩展上下文（从template，templateUrl，component或componentUrl加载路径时）
props | object | 将作为Vue / React页面组件props传递
</script></section><section  data-markdown><script type="text/template">
### Router Component(路由组件)
<font size=4>
路由器组件是一种特殊类型的内容，当我们使用component或componentUrl属性指定路由内容时，可以由路由加载。

如果您知道什么是Vue组件，那么它将更容易理解，因为它看起来非常相似。 Router Component基本上是一个具有以下属性的对象（所有属性都是可选的）

属性 | 类型 | 含义
- | - | -
template | string | Template7模板字符串。 将编译为Template7模板
render | function | 渲染函数以渲染组件。 必须返回完整的html字符串或HTMLElement
data | function | 组件数据，函数必须返回组件上下文数据
style | string | 组件CSS样式。 在将组件安装（添加到DOM）后将样式添加到文档中，并在组件被销毁（从DOM中删除）后删除
methods | object | 扩展组件上下文的其他组件方法的对象
on | object | 页面事件处理程序的对象
</script></section><section  data-markdown><script type="text/template">
组件页面事件
<font size=4>

属性 | 类型 | 含义
- | - | -
beforeCreate	| function	| 在数据和事件/观察器设置之前，在组件初始化之后立即同步调用。
created	| function	| 在创建组件后同步调用，上下文数据和方法可用，组件元素$ el也被创建并可用
beforeMount	| function	| 在将组件添加到DOM之前调用
mounted	| function	| 在将组件添加到DOM后立即调用
updated	| function	| 在组件VDOM修补后立即调用
beforeDestroy	| function	| 在组件被销毁之前调用
destroyed	| function	| 组件销毁时调用

所有生命周期钩子和方法都自动将其上下文绑定到组件上下文，以便您可以访问组件数据和方法。 这意味着您不应使用箭头函数来定义生命周期方法(e.g. created: () => this.doSomething())
</script></section><section  data-markdown><script type="text/template">
单个文件组件
```html
<!-- component template -->
<template>
  <div class="page">
    <div class="navbar">
      <div class="navbar-inner">
        <div class="title">{{title}}</div>
      </div>
    </div>
    <div class="page-content">
      <a @click="openAlert">Open Alert</a>
      <div class="list simple-list">
        <ul>
          {{#each names}}
            <li>{{this}}</li>
          {{/each}}
        </ul>
      </div>
    </div>
  </div>
</template>
<!-- component styles -->
<style scoped>
   html.ios {{this}} p {
    color: red;
  }
  .red-link {
    color: red;
  }
</style>
<!-- rest of component data and methods -->
<script>
  // script must return component object
  return {
    data: function () {
      return {
        title: 'Component Page',
        names: ['John', 'Vladimir', 'Timo'],
      }
    },
    methods: {
      openAlert: function () {
        var self = this.$app.dialog.alert('Hello world!');
      },
    },
    on: {
      pageInit: function () {
        // do something on page init
      },
      pageAfterOut: function () {
        // page has left the view
      },
    }
  }
__SCRIPT_END__
```</script></section><section  data-markdown><script type="text/template">
虚拟dom

<font size=4>
Framework7 3.1.0版提供Virtual DOM和所有VDOM相关功能。

虚拟DOM（VDOM）是一种编程概念，其中UI的理想或“虚拟”表示保存在存储器中并与“真实”DOM同步。 它允许我们ß将应用程序的视图表示为其状态的函数。

VDOM库名为[Snabbdom](https://github.com/snabbdom/snabbdom)，因为它非常轻巧，快速且非常适合Framework7环境。

那么Framework7路由器组件VDOM渲染如何工作？ 组件模板转换为VDOM，而不是直接插入DOM。 稍后，当组件状态发生更改时，它会创建新的VDOM并将其与以前的VDOM进行比较。 并且基于该差异，它通过仅更改需要更改的元素和属性来修补真实DOM。 所有这一切都自动发生！
</script></section><section  data-markdown><script type="text/template">
### route api(路由方法)
router.navigate(url, option)
<font size=4>

- url string - 要导航到的url
- options - 具有其他导航属性的对象（可选）：
    - reloadCurrent（boolean） - 用路由中的新页面替换当前页面，在这种情况下没有动画
    - reloadPrevious（boolean） - 用路由中的新页面替换历史记录中的上一页
    - reloadAll（boolean） - 加载新页面并从历史记录和DOM中删除所有以前的页面
    - clearPreviousHistory（boolean） - 重新加载/导航到指定路径后，将清除之前的页面历史记录
    - animate（boolean） - 是否应该为页面设置动画（覆盖默认路由器设置）
    - history（boolean） - 是否应将页面保存在路由器历史记录中
    - pushState（boolean） - 页面是否应保存在浏览器状态。 如果您使用pushState，那么您可以传递false以防止路由获取浏览器历史记录
    - ignoreCache（boolean） - 如果设置为true，那么它将忽略缓存中的此类URL并再次使用XHR重新加载它
    - context（object） - 附加的Router组件或Template7页面上下文
    - props（object） - 将作为Vue / React页面组件道具传递的道具
</script></section><section  data-markdown><script type="text/template">
router.back(url, options)
<font size=4>

返回上一页，返回查看历史记录

- url string - 要导航到（可选）的url。
    - 如果未指定，则它将返回历史记录中的上一页。
    - 如果指定且历史记录中有上一页，则将忽略该页面。
    - 如果指定并且存在force：true选项，则将从DOM中删除上一页并导航回指定的页面URL

- options - 具有其他导航属性的对象（可选）：
    - animate（boolean） - 是否应该为页面设置动画（覆盖默认路由器设置）
    - pushState（boolean） - 页面是否应保存在浏览器状态。 如果您使用pushState，那么您可以传递false以防止路由获取浏览  - 器历史记录
    - ignoreCache（boolean） - 如果设置为true，那么它将忽略缓存中的此类URL并再次使用XHR重新加载它
    - force（boolean） - 如果设置为true，则它将忽略历史记录中的上一页并加载指定的页面
</script></section><section  data-markdown><script type="text/template">
<font size=4>

- router.refreshPage（）刷新/重新加载当前页面。 实际上与下面相同：

```js
router.navigate（router.currentRoute.url，{

   reloadCurrent：true，

   ignoreCache：true，

}）;
```
- router.clearPreviousHistory（）清除路由器以前的页面历史记录并从DOM中删除所有以前的页面
- router.clearPreviousPages（）的工作方式与clearPreviousHistory类似，但只从DOM中删除以前的页面

</script></section><section  data-markdown><script type="text/template">
使用link代替api

<font size=5>
一直使用路由器方法在页面之间导航可能不太舒服。 在许多情况下，我们可以使用链接在页面之间导航。 我们可以使用数据属性传递其他导航参数：

```html
<!-- same as router.navigate('/somepage/'); -->
<a href="/somepage/">Some Page</a>

<!-- same as router.navigate('/somepage/', {reloadCurrent: true, animate: false}); -->
<a href="/somepage/" data-animate="false" data-reload-current="true">Some Page</a>

<!-- same as router.back(); -->
<a href="#" class="back">Go back</a>

<!-- same as router.back('/home/', {force: true, ignoreCache: true}); -->
<a href="/home/" data-force="true" data-ignore-cache="true" class="back">Go back</a>
```</script></section><section  data-markdown><script type="text/template">
### template7
<font size=5>
  Template7是一个移动优先的JavaScript模板引擎，具有类似Handlebars的语法。

它超轻量级（大约1KB缩小和压缩）并且速度极快（比移动Safari中的Handlebars快3倍！）它已经包含在Framework7中。 因此，您不需要包含任何其他脚本。
</script></section><section  data-markdown><script type="text/template">
#### 语法
<font size=5>

- | - | -
- | - | -
变量 | 区块表达式 | Helpers
{{title}} | {{join delimiter=""}} | {{#each}}...{{else}}...{{/each}}{{#each reverse="true"}}({{#variableName}}...{{/variableName}})
{{../title}} | {{escape}} | {{#if}}...{{else}}...{{/if}}
{{../../title}} | {{js "expression"}} | {{#unless}}...{{else}}...{{/unless}}
{{this}} | {{#js_if "expression"}}...{{/js_if}} | {{#with}}...{{/with}}
{{person.name}} |  | 
{{../person.name}} |  | 
{{@index}} |  |
</script></section><section  data-markdown><script type="text/template">
each

>{{#each}}...{{else}}...{{/each}}
>{{#variableName}}...{{/variableName}}

- @index -- Array
- @first -- Array
- @last -- Array
- @key -- Object
</script></section><section  data-markdown><script type="text/template">
{{js "expression"}}

>{{js "expression"}}

>{{#js_if "expression"}}...{{/js_if}}
</script></section><section  data-markdown><script type="text/template">自定义helpers

```js
Template7.registerHelper(name, helper)

name -string - helper name
helper -function - helper function to handle passed context
```</script></section><section  data-markdown><script type="text/template">
#### swipeout(滑动选项条)

元素class
<font size=5>

- swipeout-content - 列表元素的包装器。 在滑动列表项目时，此容器将移动
- swipeout-actions-left - 带有左侧滑动操作按钮/链接的容器
- swipeout-actions-right - 具有右侧滑动操作按钮/链接的容器
- swipeout-close - swipeout链接上的其他类，当您单击此链接时将关闭swipeout元素
- swipeout-delete - swipeout链接上的其他类，当您单击此链接时将删除swipeout列表项
</script></section><section  data-markdown><script type="text/template">
事件

<font size=5>

事件 | 触发时间
-|-
swipeout:open | 当swipeout元素开始打开动画时，将触发事件
swipeout:opened| swipeout元素完成其打开动画后将触发事件
swipeout:opened | 当swipeout元素开始关闭动画时，将触发事件
swipeout:closed | swipeout元素完成其关闭动画后将触发事件
swipeout:delete | swipeout元素开始删除动画后将触发事件
swipeout:deleted | swipeout元素在从DOM中删除之前完成其删除动画后将触发事件
swipeout:overswipeenter | 启用过扫描时将触发事件
swipeout:overswipeexit | 禁用过扫描时将触发事件
</script></section><section  data-markdown><script type="text/template">
方法
<font size=5>
- app.swipeout.open(el, side, callback) - 显示指定元素的swipeout操作
- app.swipeout.close(el, callback) - 关闭指定元素的swipeout操作
- app.swipeout.delete(el, callback) - 删除指定的swipeout元素
- app.swipeout.el - 属性。 目前已打开swipeout HTMLElement。 如果没有打开的swipeout元素，则为undefined</script></section></div>
    </div>

    <script src="./js/reveal.js"></script>

    <script>
      function extend() {
        var target = {};
        for (var i = 0; i < arguments.length; i++) {
          var source = arguments[i];
          for (var key in source) {
            if (source.hasOwnProperty(key)) {
              target[key] = source[key];
            }
          }
        }
        return target;
      }

      // Optional libraries used to extend on reveal.js
      var deps = [
        { src: './plugin/markdown/marked.js', condition: function() { return !!document.querySelector('[data-markdown]'); } },
        { src: './plugin/markdown/markdown.js', condition: function() { return !!document.querySelector('[data-markdown]'); } },
        { src: './plugin/highlight/highlight.js', async: true, callback: function() { hljs.initHighlightingOnLoad(); } },
        { src: './plugin/zoom-js/zoom.js', async: true },
        { src: './plugin/notes/notes.js', async: true },
        { src: './plugin/math/math.js', async: true }
      ];

      // default options to init reveal.js
      var defaultOptions = {
        controls: true,
        progress: true,
        history: true,
        center: true,
        transition: 'default', // none/fade/slide/convex/concave/zoom
        dependencies: deps
      };

      // options from URL query string
      var queryOptions = Reveal.getQueryHash() || {};

      var options = extend(defaultOptions, {}, queryOptions);
    </script>


    <script>
      Reveal.initialize(options);
    </script>
  </body>
</html>
